package com.book.common.io;

import com.google.common.collect.Sets;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.boot.context.config.ConfigFileApplicationListener;
import org.springframework.core.env.Environment;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;

import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Description：初始化配置文件
 *
 * @Author： leo.xiong
 * @CreateDate： 2019/08/21 09:00
 * @Email： leo.xiong@suyun360.com
 * Version：1.0
 */
public class PropertiesUtils {
    /**
     * 默认加载的文件，可通过继承覆盖（若有相同Key，优先加载后面的）
     */
    public static final String[] DEFAULT_CONFIG_FILE = new String[]{"classpath:application.properties", "classpath:configure/application.properties", "classpath:application.yml", "classpath:application.yml"};

    private static final String DEFAULT_ACTIVE = "default";
    private static Logger logger = PropertiesUtils.initLogger();
    private final Set<String> configSet = Sets.newLinkedHashSet();
    private final Properties properties = new Properties();

    /**
     * 正则表达式预编译
     */
    private static Pattern p1 = Pattern.compile("\\$\\{.*?\\}");

    private static Environment environment;

    private static final class PropertiesLoaderHolder {


        private static PropertiesUtils INSTANCE;

        static {
            reloadInstance();
        }

        private static void reloadInstance() {
            Set<String> configSet = Sets.newLinkedHashSet();
            Resource[] resources = ResourceUtils.getResources("classpath*:/book-core.*");
            for (Resource resource : resources) {
                configSet.add("classpath:" + resource.getFilename());
            }
            /**
             * 获取全局设置默认的配置文件（以下是支持环境配置的属性文件）
             */
            Set<String> set = Sets.newLinkedHashSet();
            for (String configFile : DEFAULT_CONFIG_FILE) {
                set.add(configFile);
            }
            String[] configFiles = set.toArray(new String[set.size()]);
            String profiles = System.getProperty(ConfigFileApplicationListener.ACTIVE_PROFILES_PROPERTY);
            if (StringUtils.isEmpty(profiles)) {
                PropertiesUtils propsTemp = new PropertiesUtils(configFiles);
                profiles = propsTemp.getProperty(ConfigFileApplicationListener.ACTIVE_PROFILES_PROPERTY);
                if (StringUtils.isEmpty(profiles) || DEFAULT_ACTIVE.equals(profiles)) {
                    Resource[] activeProfileResource = ResourceUtils.getResources("classpath*:application-*.*");
                    if (activeProfileResource != null && activeProfileResource.length > 0 && activeProfileResource[0] != null) {
                        profiles = activeProfileResource[0].getFilename().split("-")[1].split("\\.")[0];
                    }
                }
            }
            for (String location : configFiles) {
                configSet.add(location);
                if (StringUtils.isNotBlank(profiles)) {
                    if (location.endsWith(".properties")) {
                        configSet.add(StringUtils.substringBeforeLast(location, ".properties")
                                + "-" + profiles + ".properties");
                    } else if (location.endsWith(".yml")) {
                        configSet.add(StringUtils.substringBeforeLast(location, ".yml")
                                + "-" + profiles + ".yml");
                    }
                }
            }
            configFiles = configSet.toArray(new String[configSet.size()]);
            logger.debug("Loading book configure: {}", (Object) configFiles);
            INSTANCE = new PropertiesUtils(configFiles);
        }
    }

    /**
     * 载入多个文件，路径使用Spring Resource格式，相同的属性在最后载入的文件中的值将会覆盖之前的值。
     */
    public PropertiesUtils(String... configFiles) {
        for (String location : configFiles) {
            try {
                Resource resource = ResourceUtils.getResource(location);
                if (resource.exists()) {
                    if (location.endsWith(".properties")) {
                        try (InputStreamReader is = new InputStreamReader(resource.getInputStream(), "UTF-8")) {
                            properties.load(is);
                            configSet.add(location);
                        } catch (IOException ex) {
                            logger.error("Load " + location + " failure. ", ex);
                        }
                    } else if (location.endsWith(".yml")) {
                        YamlPropertiesFactoryBean bean = new YamlPropertiesFactoryBean();
                        bean.setResources(resource);
                        for (Map.Entry<Object, Object> entry : bean.getObject().entrySet()) {
                            //properties.getProperty方法会把值类型不是String的赋值为空
                            properties.put(entry.getKey(), entry.getValue() != null ? entry.getValue().toString() : null);
                        }
                        configSet.add(location);
                    }
                }
            } catch (Exception e) {
                logger.error("Load " + location + " failure. ", e);
            }
        }
    }

    /**
     * 获取属性值，取不到从System.getProperty()获取，都取不到返回null
     */
    public String getProperty(String key) {
        if (environment != null) {
            String value = environment.getProperty(key);
            if (value != null) {
                return value;
            }
        }
        String value = properties.getProperty(key);
        if (value != null) {
            Matcher m = p1.matcher(value);
            while (m.find()) {
                String g = m.group();
                String childKey = g.replaceAll("\\$\\{|\\}", "");
                value = StringUtils.replace(value, g, getProperty(childKey));
            }
            return value;
        } else {
            String systemProperty = System.getProperty(key);
            if (systemProperty != null) {
                return systemProperty;
            }
        }
        return null;
    }

    public static PropertiesUtils getInstance() {
        return PropertiesLoaderHolder.INSTANCE;
    }

    public Properties getProperties() {
        return properties;
    }

    /**
     * 初始化日志路径
     */
    private static Logger initLogger() {
        String logPath = null;
        try {
            // 获取当前classes目录
            logPath = new DefaultResourceLoader().getResource("/").getFile().getPath();
        } catch (Exception e) {
            // 取不到，取当前工作路径
            logPath = System.getProperty("user.dir");
        }
        // 取当前日志路径下有classes目录，则使用classes目录
        String classesLogPath = FileUtils.path(logPath + "/WEB-INF/classes");
        if (new File(classesLogPath).exists()) {
            logPath = classesLogPath;
        }
        if (StringUtils.isBlank(System.getProperty("logPath"))) {
            System.setProperty("logPath", FileUtils.path(logPath));
        }
        return LoggerFactory.getLogger(PropertiesUtils.class);
    }
}
